#include "native-lib.h"
#include "utils/HttpClient.h"
#include <android/bitmap.h>

using namespace img;
using namespace mahjong;
using namespace utils;

extern "C" {

Prt<Mahjong> autoMj;
Prt<Callinterface> call;

JavaVM *g_javaVm = nullptr;
jclass g_mahjongClass;
jclass g_userBoardClass;
jclass g_boardInfoClass;
Prt<Image> image;


JNIEXPORT void JNICALL
Java_mahjong_auto_com_os_Mahjong_init(JNIEnv *env, jclass type) {
    env->GetJavaVM(&g_javaVm);

    g_mahjongClass = (jclass) env->NewGlobalRef(env->FindClass("mahjong/auto/com/os/Mahjong"));
    g_userBoardClass = (jclass) env->NewGlobalRef(env->FindClass("mahjong/auto/com/os/UserBoard"));
    g_boardInfoClass = (jclass) env->NewGlobalRef(
            env->FindClass("mahjong/auto/com/os/BoardInfo")); //或得Student类引用

    CodeImage::setInterface(new CodeImg());
    call = new Call();
    autoMj = new Mahjong(call);
}


JNIEXPORT void JNICALL
Java_mahjong_auto_com_os_Mahjong_destroy(JNIEnv *env, jclass type) {

    env->DeleteGlobalRef(g_boardInfoClass);
    env->DeleteGlobalRef(g_userBoardClass);
    env->DeleteGlobalRef(g_mahjongClass);
}

JNIEXPORT void JNICALL
Java_mahjong_auto_com_os_Mahjong_discern(JNIEnv *env, jclass type, jobject bitmap) {
    if (NULL == bitmap) {
        __android_log_print(ANDROID_LOG_DEBUG, "native", "bitmap is NULL");
        return;
    }

    AndroidBitmapInfo info;
    if (ANDROID_BITMAP_RESULT_SUCCESS != AndroidBitmap_getInfo(env, bitmap, &info)) {
        __android_log_print(ANDROID_LOG_DEBUG, "native", "get bitmap info failed");
        return;
    }

    void *bitData;
    if (ANDROID_BITMAP_RESULT_SUCCESS != AndroidBitmap_lockPixels(env, bitmap, &bitData)) {
        __android_log_print(ANDROID_LOG_DEBUG, "native", "lock src bitmap failed");
        return;
    }

    Prt<Image> image = new Image();
    image->setWidth(info.width);
    image->setWidth(info.height);
    image->setFormat((ImageFormat) info.format);
    image->setpData(bitData);

    image = EditImage::get()->zoomImage_Near(image, 1280, 720);
    autoMj->discern(image);

    if (ANDROID_BITMAP_RESULT_SUCCESS != AndroidBitmap_unlockPixels(env, bitmap)) {
        __android_log_print(ANDROID_LOG_DEBUG, "native", "unlock src bitmap failed");
        return;
    }

//    Socket socket;
//    socket.Connect("192.168.0.104", 6832);
//    socket.Close();
}


JNIEXPORT void JNICALL
Java_mahjong_auto_com_os_Mahjong_test(JNIEnv *env, jclass type, jobject bitmap) {

    if (NULL == bitmap) {
        __android_log_print(ANDROID_LOG_DEBUG, "native", "bitmap is NULL");
        return;
    }

    AndroidBitmapInfo info;
    if (ANDROID_BITMAP_RESULT_SUCCESS != AndroidBitmap_getInfo(env, bitmap, &info)) {
        __android_log_print(ANDROID_LOG_DEBUG, "native", "get bitmap info failed");
        return;
    }

    void *bitData;
    if (ANDROID_BITMAP_RESULT_SUCCESS != AndroidBitmap_lockPixels(env, bitmap, &bitData)) {
        __android_log_print(ANDROID_LOG_DEBUG, "native", "lock src bitmap failed");
        return;
    }


    autoMj->login("18990855828","19880727");


    if (ANDROID_BITMAP_RESULT_SUCCESS != AndroidBitmap_unlockPixels(env, bitmap)) {
        __android_log_print(ANDROID_LOG_DEBUG, "native", "unlock src bitmap failed");
        return;
    }

}



}

Prt<Image> CodeImg::loadImage(const string &path) {
    Prt<Image> ret;
    if (0 == path.size())
        return ret;

    JniEnv env;
    if (env.isNULL())
        return ret;

    jclass mahjong = env->FindClass("mahjong/auto/com/os/Mahjong");

    jmethodID load = env->GetStaticMethodID(mahjong, "loadBitmap",
                                            "(Ljava/lang/String;)Landroid/graphics/Bitmap;");

    jobject bitmap = env->CallStaticObjectMethod(mahjong, load, env->NewStringUTF(path.c_str()));

    AndroidBitmapInfo info;
    if (ANDROID_BITMAP_RESULT_SUCCESS != AndroidBitmap_getInfo(*env, bitmap, &info)) {
        __android_log_print(ANDROID_LOG_DEBUG, "native", "get bitmap info failed");
        return ret;
    }

    void *bitData;
    if (ANDROID_BITMAP_RESULT_SUCCESS != AndroidBitmap_lockPixels(*env, bitmap, &bitData)) {
        __android_log_print(ANDROID_LOG_DEBUG, "native", "lock src bitmap failed");
        return ret;
    }

    ret = new Image(info.width, info.height, bitData, (ImageFormat) info.format);
    memcpy(bitData, ret->getData(), info.stride * info.height);

    if (ANDROID_BITMAP_RESULT_SUCCESS != AndroidBitmap_unlockPixels(*env, bitmap)) {
        __android_log_print(ANDROID_LOG_DEBUG, "native", "unlock src bitmap failed");
        return ret;
    }
    return ret;
}

jarray Call::getArray(Prt<vector<MahjongEnum>> &arrays) {
    JniEnv env;
    if (env.isNULL() || 0 == arrays->size())
        return nullptr;

    jintArray jarray = env->NewIntArray(arrays->size());
    jint *intValue = env->GetIntArrayElements(jarray, NULL);
    jint *temp = intValue;

    for (vector<mahjong::MahjongEnum>::iterator item = arrays->begin();
         item != arrays->end(); ++item, ++temp) {

        *temp = *item;
    }
    env->ReleaseIntArrayElements(jarray, intValue, JNI_COMMIT);
    return jarray;
}

jobject Call::getUserBoard(Prt<UserBoard> &prt) {
    jobject userBoard = mEnv->NewObject(g_userBoardClass, jUserBoard_init);  //构造一个对象

    mEnv->CallVoidMethod(userBoard, jUserBoard_setBoard, getArray(prt->getBoard()));
    mEnv->CallVoidMethod(userBoard, jUserBoard_setOpen, getArray(prt->getOpen()));
    mEnv->CallVoidMethod(userBoard, jUserBoard_setOut, getArray(prt->getOut()));
    mEnv->CallVoidMethod(userBoard, jUserBoard_setIsDealer, (jboolean) prt->isDealer());
    mEnv->CallVoidMethod(userBoard, jUserBoard_setLackBoard, (jint) prt->getLackBoard());

    return userBoard;
}

void Call::info(Prt<BoardInfo> &info) {
    jobject boardInfo = mEnv->NewObject(g_boardInfoClass, jBoardInfo_Init);  //构造一个对象

    mEnv->CallVoidMethod(boardInfo, jBoardInfo_setMe, getUserBoard(info->getMe()));
    mEnv->CallVoidMethod(boardInfo, jBoardInfo_setTop, getUserBoard(info->getTop()));
    mEnv->CallVoidMethod(boardInfo, jBoardInfo_setDown, getUserBoard(info->getDown()));
    mEnv->CallVoidMethod(boardInfo, jBoardInfo_setUp, getUserBoard(info->getUp()));

    mEnv->CallStaticVoidMethod(g_mahjongClass, jMahjong_info, boardInfo);
}

bool Call::simulateClick(int x, int y) {
    return mEnv->CallStaticBooleanMethod(g_mahjongClass, jMahjong_simulateClick, x, y);
}


Call::Call() {
    jMahjong_simulateClick = mEnv->GetStaticMethodID(g_mahjongClass, "simulateClick", "(II)Z");

    jBoardInfo_Init = mEnv->GetMethodID(g_boardInfoClass, "<init>", "()V");
    jBoardInfo_setUp = mEnv->GetMethodID(g_boardInfoClass, "setUp",
                                         "(Lmahjong/auto/com/os/UserBoard;)V");
    jBoardInfo_setDown = mEnv->GetMethodID(g_boardInfoClass, "setDown",
                                           "(Lmahjong/auto/com/os/UserBoard;)V");
    jBoardInfo_setTop = mEnv->GetMethodID(g_boardInfoClass, "setTop",
                                          "(Lmahjong/auto/com/os/UserBoard;)V");
    jBoardInfo_setMe = mEnv->GetMethodID(g_boardInfoClass, "setMe",
                                         "(Lmahjong/auto/com/os/UserBoard;)V");
    jMahjong_info = mEnv->GetStaticMethodID(g_mahjongClass, "info",
                                            "(Lmahjong/auto/com/os/BoardInfo;)V");

    jUserBoard_init = mEnv->GetMethodID(g_userBoardClass, "<init>", "()V");
    jUserBoard_setBoard = mEnv->GetMethodID(g_userBoardClass, "setBoard", "([I)V");
    jUserBoard_setOpen = mEnv->GetMethodID(g_userBoardClass, "setOpen", "([I)V");
    jUserBoard_setOut = mEnv->GetMethodID(g_userBoardClass, "setOut", "([I)V");
    jUserBoard_setIsDealer = mEnv->GetMethodID(g_userBoardClass, "setIsDealer", "(Z)V");
    jUserBoard_setLackBoard = mEnv->GetMethodID(g_userBoardClass, "setLackBoard", "(I)V");
}

JniEnv::JniEnv() :
        mAttated(false),
        mEnv(nullptr) {

    if (0 > g_javaVm->GetEnv((void **) &mEnv, JNI_VERSION_1_6)) {
        if (0 > g_javaVm->AttachCurrentThread(&mEnv, NULL)) {
            return;
        }
        mAttated = true;
    }
    mVersion = JNI_VERSION_1_6;
}

bool JniEnv::isNULL() {
    return nullptr == mEnv;
}

JniEnv::~JniEnv() {
    if (mAttated)
        g_javaVm->DetachCurrentThread();
}

JNIEnv *JniEnv::operator->() {
    return mEnv;
}

JNIEnv *JniEnv::operator*() {
    return mEnv;
}

int JniEnv::getVersion() const {
    return mVersion;
}


